#ifndef CTableH
#define CTableH

#include "CtrlDB.h"
#include <DBTables.hpp>
#include <BDE.hpp>

#include <EIC.h>


enum TTypeTable { ttCommun, ttDossier, ttTmp, ttLibre, ttCommunLocal ,ttTableDossiers};
typedef unsigned int FilterID;
#define FID_NUL ((FilterID)0)


//********//
// CTable //
//********//////////////////////////////////////////////////////////////////////
//                                                                            //
//    Cette classe surcharge la classe VCL TTable pour lui adjoindre la       //
// gestion des tables EIC (Base de données et Nom de table) via les propriétés//
// EIC*, désactiver la gestion de définition de champs (qui ne gère pas les   //
// valeurs par défaut des champs) et ajouter des opérations de modification   //
// de structure, de copie de table et de gestion des filtres.                 //
//                                                                            //
// Note : Quelque soit le type d'une table CTable, on peut préciser son nom   //
//        complet directement (propriété "TableName"); toutefois, pour les    //
//        table de type non libre, si le code de la table est précisé, il     //
//        prévaut sur le nom de la table.                                     //
////////////////////////////////////////////////////////////////////////////////
class PACKAGE_CTRLDB CTable : public TTable
{
 private:
  TTypeTable m_eTypeTable;     // Type de la table
  AnsiString m_strCodeTable;   // Code de la table
  void*      m_pvFiltersStack; // Pile de filtres

  bool __fastcall StoreDatabaseName( void) const { return( m_eTypeTable == ttLibre);}
  bool __fastcall StoreExclusive( void)    const { return( Exclusive && ( m_eTypeTable != ttTmp));}
  bool __fastcall StoreTableName( void)    const { return( m_strCodeTable.IsEmpty());}
  void __fastcall SetEICCodeTable( const AnsiString strCodeTable);
  void __fastcall SetEICTypeTable( TTypeTable eTypeTable);

 public:
   Variant __fastcall GetPrecField ( TField *pField, int nStep = -1);
   void    __fastcall CopyPrecField( TField *pField, int nStep = -1);

 __published:
  __property DatabaseName = { stored = StoreDatabaseName};
  __property Exclusive    = { stored = StoreExclusive};
  __property FieldDefs;
  __property StoreDefs;
  __property TableName    = { stored = StoreTableName};
  __property AnsiString EICCodeTable = { read = m_strCodeTable, write = SetEICCodeTable                     };
  __property TTypeTable EICTypeTable = { read = m_eTypeTable,   write = SetEICTypeTable, default = ttDossier};


 //*********************************//
 // Opérations sur une table fermée //
 //*********************************//
 public:
  static bool __fastcall FieldExists( const CURProps* pcpropsTbl, const FLDDesc* pcFldDescs, const char* pcszFldName, Word *iFld0Num);
  void __fastcall GetBDEDescs( hDBIDb& hdb, CRTblDesc& tbldesc, CURProps& propsTbl, FLDDesc*& pFldDescs, CROpType*& pOps, VCHKDesc** ppvchkDescs = NULL);
  void __fastcall GetBDEDescs(hDBIDb *hdb, CRTblDesc *tblDesc, CURProps *propsTbl = NULL, VCHKDesc** ppvchkDescs = NULL);
  static bool __fastcall CopyTable(const AnsiString &TableSource,const AnsiString &TableDestination,bool bOverwrite = false);
  bool __fastcall Copy( const EICTag tag, const char* pcszCopyName, bool bOverwrite = false, int hInstance = (int)HInstance) const;
  bool __fastcall AddField( const EICTag   tag,
                            const char*    pcszFldName,
                            Word           efldPDXType,                      // Une valeur fldPDX* restreinte
                            Word           wInsertPos0     = 0xFFFF,
                            unsigned short ushMaxStringLen = 0,              // Ignoré si efldPDXType != fldPDXCHAR
                            bool           bObligatoire    = false,
                            void*          pvDefaultValue  = NULL,
                            int            hInstance       = (int)HInstance);
  bool __fastcall DropField( const EICTag tag,
                             const char*  pcszFldName,
                             int          hInstance = (int)HInstance);
  bool __fastcall ChangeFieldType( const EICTag   tag,
                                   const char*    pcszFldName,
                                   Word           efldPDXType,                    // Une valeur fldPDX* restreinte
                                   unsigned short ushMaxDataLen = 0xFFFF,         // Ignoré si efldPDXType != fldPDXCHAR && efldPDXType != fldPDXMEMO
                                   int            hInstance     = (int)HInstance);
  bool __fastcall ChangeValChk( const EICTag tag,
                                const char*  pcszFldName,
                                bool         bObligatoire   = false,
                                void*        pvDefaultValue = NULL,
                                int          hInstance      = (int)HInstance,
                                void*       pvMinValue = NULL,
                                void*       pvMaxValue = NULL);
  void __fastcall UpgradeLevel( const EICTag tag,
                                int          hInstance = (int)HInstance);
  void __fastcall CreateTable( bool bOverWrite,
                               int nFields    , FLDDesc  *pfldDesc,
                               char *szLangageTable,
                               int nIndexs = 0, IDXDesc  *pidxDesc = NULL,
                               int nChecks = 0, VCHKDesc *pchkDesc = NULL
                               );
  void __fastcall CreateTable( bool bOverWrite,
                               int nFields    , FLDDesc  *pfldDesc,
                               int nIndexs = 0, IDXDesc  *pidxDesc = NULL,
                               int nChecks = 0, VCHKDesc *pchkDesc = NULL
                               );
  void __fastcall CreateTable();
  void __fastcall LocateNearest( const AnsiString &strFieldName, const AnsiString &strText);
  bool __fastcall RenommerChamp(const char*    pcszFldNameSource,
                                const char*    pcszFldNameCible);


 //********************************************//
 // Opérations sur une table ouverte ou fermée //
 //********************************************//
 public:
  void __fastcall PushFilter( FilterID& fidPushed, const AnsiString& strNewFilter, bool bDoFilter = true);
  void __fastcall PushFilter( FilterID& fidPushed);
  void __fastcall PopFilter( FilterID& fidToPop);


 //**********************************//
 // Opérations sur une table ouverte //
 //**********************************//
   /*HIDESBASE*/ //bool __fastcall IsEmpty(void);
 private:
  void __fastcall Init( TTypeTable eTypeTable, const char* pcszTableName = NULL);

 public:
  __fastcall CTable( TComponent* pOwner);
  __fastcall CTable( TTypeTable  eTypeTable, // ttLibre déconseillé sinon TableName = EICCodeTable
                     const char* pcszCodeTable,
                     TComponent* pOwner     = /*Applicationtoto*/0);
  __fastcall CTable( const char* pcszTableName,
                     TTypeTable  eTypeTable, // ttLibre conseillé
                     TComponent* pOwner     = /*Applicationtoto*/0);
  bool __fastcall IndexExists( const AnsiString &strIndexName);
  virtual __fastcall ~CTable( void);
}; /* class CTable */
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#define INIT_PARADOX_FIELD_LONG( fldDesc, nFieldNum, szFieldName) {                      \
                                 ::ZeroMemory(( fldDesc + nFieldNum), sizeof( FLDDesc)); \
                                 ( fldDesc + nFieldNum)->iFldNum  = nFieldNum;           \
                                 ( fldDesc + nFieldNum)->iFldType = fldPDXLONG;          \
                                 strcpy(( fldDesc + nFieldNum)->szName, szFieldName);    \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_FIELD_CHAR( fldDesc, nFieldNum, szFieldName, nSize) {               \
                                 ::ZeroMemory(( fldDesc + nFieldNum), sizeof( FLDDesc)); \
                                 ( fldDesc + nFieldNum)->iFldNum  = nFieldNum;           \
                                 ( fldDesc + nFieldNum)->iFldType = fldPDXCHAR;          \
                                 ( fldDesc + nFieldNum)->iUnits1  = nSize;               \
                                 strcpy(( fldDesc + nFieldNum)->szName, szFieldName);    \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_FIELD_BOOL( fldDesc, nFieldNum, szFieldName) {                      \
                                 ::ZeroMemory(( fldDesc + nFieldNum), sizeof( FLDDesc)); \
                                 ( fldDesc + nFieldNum)->iFldNum  = nFieldNum;           \
                                 ( fldDesc + nFieldNum)->iFldType = fldPDXBOOL;          \
                                 strcpy(( fldDesc + nFieldNum)->szName, szFieldName);    \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_FIELD_CURRENCY( fldDesc, nFieldNum, szFieldName) {                      \
                                     ::ZeroMemory(( fldDesc + nFieldNum), sizeof( FLDDesc)); \
                                     ( fldDesc + nFieldNum)->iFldNum  = nFieldNum;           \
                                     ( fldDesc + nFieldNum)->iFldType = fldPDXMONEY;         \
                                     strcpy(( fldDesc + nFieldNum)->szName, szFieldName);    \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_FIELD_DATE( fldDesc, nFieldNum, szFieldName) {                      \
                                 ::ZeroMemory(( fldDesc + nFieldNum), sizeof( FLDDesc)); \
                                 ( fldDesc + nFieldNum)->iFldNum  = nFieldNum;           \
                                 ( fldDesc + nFieldNum)->iFldType = fldPDXDATE;          \
                                 strcpy(( fldDesc + nFieldNum)->szName, szFieldName);    \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_FIELD_DATETIME( fldDesc, nFieldNum, szFieldName) {                      \
                                     ::ZeroMemory(( fldDesc + nFieldNum), sizeof( FLDDesc)); \
                                     ( fldDesc + nFieldNum)->iFldNum  = nFieldNum;           \
                                     ( fldDesc + nFieldNum)->iFldType = fldPDXDATETIME;      \
                                     strcpy(( fldDesc + nFieldNum)->szName, szFieldName);    \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_FIELD_FLOAT( fldDesc, nFieldNum, szFieldName) {                      \
                                  ::ZeroMemory(( fldDesc + nFieldNum), sizeof( FLDDesc)); \
                                  ( fldDesc + nFieldNum)->iFldNum  = nFieldNum;           \
                                  ( fldDesc + nFieldNum)->iFldType = fldPDXNUM;           \
                                  strcpy(( fldDesc + nFieldNum)->szName, szFieldName);    \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_FIELD_AUTOINC( fldDesc, nFieldNum, szFieldName) {                      \
                                    ::ZeroMemory(( fldDesc + nFieldNum), sizeof( FLDDesc)); \
                                    ( fldDesc + nFieldNum)->iFldNum  = nFieldNum;           \
                                    ( fldDesc + nFieldNum)->iFldType = fldPDXAUTOINC;       \
                                    strcpy(( fldDesc + nFieldNum)->szName, szFieldName);    \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_FIELD_MEMO( fldDesc, nFieldNum, szFieldName, nSizeHeader) {         \
                                 ASSERT(( nSizeHeader>=1) && ( nSizeHeader<=240));       \
                                 ::ZeroMemory(( fldDesc + nFieldNum), sizeof( FLDDesc)); \
                                 ( fldDesc + nFieldNum)->iFldNum  = nFieldNum;           \
                                 ( fldDesc + nFieldNum)->iFldType = fldPDXMEMO;          \
                                 ( fldDesc + nFieldNum)->iUnits1  = nSizeHeader;         \
                                 strcpy(( fldDesc + nFieldNum)->szName, szFieldName);    \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_VCHECK( chkDesk, nFieldNum, bReq) {                 \
                             ::ZeroMemory( &chkDesk, sizeof( VCHKDesc)); \
                             chkDesk.iFldNum   = nFieldNum+1;            \
                             chkDesk.bRequired = bReq;                   \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_VCHECK( chkDesk, nFieldNum, bReq) {                 \
                             ::ZeroMemory( &chkDesk, sizeof( VCHKDesc)); \
                             chkDesk.iFldNum   = nFieldNum+1;            \
                             chkDesk.bRequired = bReq;                   \
        }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#define INIT_PARADOX_INDEX_PRIMAIRE_1( idxDesc) {                                 \
                                       strcpy( idxDesc.szName, "Primary");        \
                                       ::ZeroMemory( &idxDesc, sizeof( IDXDesc)); \
                                       idxDesc.iIndexId    = 0;                   \
                                       idxDesc.bPrimary    = TRUE;                \
                                       idxDesc.iFldsInKey  = 1;                   \
                                       idxDesc.aiKeyFld[0] = 1;                   \
                                       idxDesc.bCaseInsensitive = FALSE;          \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_INDEX_PRIMAIRE_2( idxDesc) {                               \
                                       INIT_PARADOX_INDEX_PRIMAIRE_1( idxDesc); \
                                       idxDesc.iFldsInKey  = 2;                 \
                                       idxDesc.aiKeyFld[1] = 2;                 \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_INDEX_PRIMAIRE_3( idxDesc) {                               \
                                       INIT_PARADOX_INDEX_PRIMAIRE_2( idxDesc); \
                                       idxDesc.iFldsInKey  = 3;                 \
                                       idxDesc.aiKeyFld[2] = 3;                 \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_INDEX_PRIMAIRE_4( idxDesc) {                               \
                                       INIT_PARADOX_INDEX_PRIMAIRE_3( idxDesc); \
                                       idxDesc.iFldsInKey  = 4;                 \
                                       idxDesc.aiKeyFld[3] = 4;                 \
        }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#define INIT_PARADOX_INDEX_1( idxDesc, szIndexName, nFieldNum0) {        \
                              ::ZeroMemory( &idxDesc, sizeof( IDXDesc)); \
                              strcpy( idxDesc.szName, szIndexName);      \
                              idxDesc.iFldsInKey  = 1;                   \
                              idxDesc.aiKeyFld[0] = nFieldNum0+1;        \
                              idxDesc.bCaseInsensitive = TRUE;           \
                              idxDesc.bMaintained      = TRUE;           \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_INDEX_2( idxDesc, szIndexName, nFieldNum0, nFieldNum1) {          \
                              INIT_PARADOX_INDEX_1( idxDesc, szIndexName, nFieldNum0); \
                              idxDesc.iFldsInKey  = 2;                                 \
                              idxDesc.aiKeyFld[1] = nFieldNum1+1;                      \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_INDEX_3( idxDesc, szIndexName, nFieldNum0, nFieldNum1, nFieldNum2) {          \
                              INIT_PARADOX_INDEX_2( idxDesc, szIndexName, nFieldNum0, nFieldNum1); \
                              idxDesc.iFldsInKey  = 3;                                             \
                              idxDesc.aiKeyFld[2] = nFieldNum2+1;                                  \
        }
//---------------------------------------------------------------------------
#define INIT_PARADOX_INDEX_4( idxDesc, szIndexName, nFieldNum0, nFieldNum1, nFieldNum2, nFieldNum3) {          \
                              INIT_PARADOX_INDEX_3( idxDesc, szIndexName, nFieldNum0, nFieldNum1, nFieldNum2); \
                              idxDesc.iFldsInKey  = 4;                                                         \
                              idxDesc.aiKeyFld[3] = nFieldNum3+1;                                              \
        }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#define SCAN_TABLE( tbl)           for( tbl->First(); !tbl->Eof; tbl->Next ())
#define REVERSE_SCAN_TABLE( tbl)   for( tbl->Last (); !tbl->Bof; tbl->Prior())
#define BOOKMARK_SCAN_TABLE( tbl, code)  { tbl->DisableControls(); \
                                           tbl->Refresh(); \
                                           AnsiString strBookmark( tbl->Bookmark); \
                                           SCAN_TABLE( tbl) { code } \
                                           tbl->Bookmark = strBookmark; \
                                           tbl->EnableControls(); \
                                         }
//---------------------------------------------------------------------------
// Permet d'écrire des 'Filter' pour les 'TDataSet' et dérivé plus compréhensible.
// Exemple auparavant vous auriez écrit quelques choses de ce style
// tblTable->Filter = tblCompte->FieldName + "='" + strCompte + "' AND (" + tblDateEP->FieldName + "='" + dtDate.DateString() + "' OR (" +
//                    tblDateEP->FieldName + "<'" + dtDate.DateString() + "' AND (" + tblDatePointage->FieldName + " IS NULL OR " +
//                    tblDatePointage->FieldName + "='" + dtDate.DateString() + "'))))";
// Maintenant vous écrirez votre expression comme ceci '( fc=c AND ( fd=d OR ( fd<d AND ( fp IS NULL OR fp=d))))'
// plus simple à comprendre et à maintenir. Où fc, fd, fp, c et d sont des variables à définir à l'appel
// de la fonction ainsi que leur valeur.
// Il existe 4 types de variables FIELD, STRING, DATE et INT.
// La syntaxe pour écrire le définition se fait comme ceci
// TYPEVARIABLE1:nomvar1[,nonvar2,...][;TYPEVARIABLE2:nomvar1[,nonvar2,...]]
// Pour notre exemple ci-dessus on aurait écrit "FIELD:fc,fd,fp;STRING:c;DATE:d"
// Ensuite, il faut donner les valeurs pour chaque variable dans le sens où elles sont été déclarées.
// Pour le type FIELD, il faut passer un 'TField*' ou dérivé, pour le type STRING un 'char*',
// pour le type DATE un 'int' (cast du TDateTime en int) et pour le type INT, je vous laisse deviner.
// Donc l'exemple peut s'écrire maintenant:
// tblTable->Filter = MakeFilter( "( fc=c AND ( fd=d OR ( fd<d AND ( fp IS NULL OR fp=d))))", "FIELD:fc,fd,fp;STRING:c;DATE:d",
//                                tblCompte, tblDateEP, tblDatePointage, strCompte.c_str(), ( int)dtValue);
// REMARQUES IMPORTANTES: les noms des variables sont impérativement écrites en MINUSCULES
//  et les commandes ( AND, OR, ...) impérativement écrites en MAJUSCULES.
// Pour les filtres simples cette fonction n'est surement pas le plus rapide mais trouve tout
// son intérêt pour des formules très complexes.
extern PACKAGE_CTRLDB AnsiString __cdecl MakeFilter( const char *szExpression, const char *szVars, ...);
//---------------------------------------------------------------------------
#endif
